#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
	arbre=programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
	// <programme> ::= debut <seq_inst> fin FIN_FICHIER

	sauterSymCour("debut");
	Noeud* si = seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
	// <seqInst> ::= <inst> ; { <inst> ; }

	NoeudSeqInst* si = new NoeudSeqInst();
	do {
		si->ajouteInstruction(inst());
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="si" || ls.getSymCour()=="tantque"
                || ls.getSymCour()=="repeter" || ls.getSymCour()=="pour" || ls.getSymCour()=="lire"
                || ls.getSymCour()=="ecrire");
	// tant que le symbole courant est un debut possible d'instruction...
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst() {
// <inst> ::= <affectation> | <inst_condi>
if (ls.getSymCour()=="si") return instSi();
else if (ls.getSymCour()=="tantque") return instTq();
else if (ls.getSymCour()=="repeter") return instRepeter();
else if (ls.getSymCour()=="pour") return instPour();
else if (ls.getSymCour()=="lire") return instLire();
else if (ls.getSymCour()=="ecrire") return instEcrire();
else return affectation();

}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instSi() {
    //<instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> } [ sinon <seqInst> ] finsi
    Noeud* seq1 = NULL;
    vector<NoeudInstCond*> TabSi; //tableau avec element Instruction avec Condition en premier le Si puis tout les sinonsi
    sauterSymCour("si");
    sauterSymCour("(");
    Noeud* cond = expBool();
    sauterSymCour(")");
    Noeud* seq = seqInst();
    NoeudInstCond* Inst = new NoeudInstCond(cond,seq); //création de l'élement instruction avec condition dans le cas du si
    TabSi.push_back(Inst); //ajout de l'élement dans le vecteur
    
    while (ls.getSymCour() == "sinonsi") {
        sauterSymCour("sinonsi");
        sauterSymCour("(");
        cond = expBool();
        sauterSymCour(")");
        seq = seqInst();
    NoeudInstCond* Inst = new NoeudInstCond(cond,seq); //création de l'élement instruction avec condition dans le cas d'un sinonsi
    TabSi.push_back(Inst); //ajout de l'élement dans le vecteur
        
    }
    if (ls.getSymCour() == "sinon") {
        sauterSymCour("sinon");
        seq1 = seqInst();
    }
    sauterSymCour("finsi");
    return new NoeudInstSi(TabSi,seq1);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instTq() {
    //<instTq> ::= tantque ( <expBool> ) <seqInst> fintantque
 
    sauterSymCour("tantque");
    sauterSymCour("(");
    Noeud* cond = expBool();
    sauterSymCour(")");
    Noeud* seq= seqInst();
    sauterSymCour("fintantque");
    return new NoeudInstTq(cond,seq); 
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instRepeter() {
  //<instRepeter::= repeter <seqInst> jusqua ( <expBool> )
    sauterSymCour("repeter");
    sauterSymCour("(");
    Noeud* seq = seqInst();
    sauterSymCour(")");
    sauterSymCour("jusqua");
    sauterSymCour("(");
    Noeud* cond = expBool();
    sauterSymCour(")");
    return new NoeudInstRepeter(cond,seq); 
    
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instPour() {
    //<instPour::= pour (<affectation> ; <relation> ; <affectation> ) <seqInst> finpour
    sauterSymCour("pour");
    sauterSymCour("(");
    Noeud* ini = affectation();
    sauterSymCour(";");
    Noeud* cond = relation();
    sauterSymCour(";");
    Noeud* inc = affectation();
    sauterSymCour(")");
    Noeud* seq = seqInst();
    sauterSymCour("finpour");
    return new NoeudInstPour(ini,cond,inc,seq);
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instLire() {
        //instLire> ::= lire ( <variable> )  
    int val;
    
    sauterSymCour("lire");
    sauterSymCour("(");
    testerSymCour("<VARIABLE>");
    Noeud* var = ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour(")");
    cin >> val;
    return new NoeudInstLire(var,val);
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instEcrire(){
      //<instEcrire> ::= ecrire ( <expression> | <chaine> )
    Noeud* exp = NULL;
    NoeudInstEcrire* nIE;
    sauterSymCour("ecrire");
    sauterSymCour("(");
    if (ls.getSymCour()=="<CHAINE>") {
        exp = ts.chercheAjoute(ls.getSymCour());
        cout << ls.getSymCour().getChaine() << endl;
        ls.suivant();
        
    }
    else exp = expression();
    sauterSymCour(")");
    return nIE = new NoeudInstEcrire(exp);


}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expression>

	testerSymCour("<VARIABLE>");
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	Noeud* exp = expression();
	return new NoeudAffectation(var,exp);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
// <expression> ::= <terme> { <op> <terme> }

	Noeud* term = terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
		Symbole operateur = opAdd(); // on stocke le symbole de l'opérateur
		Noeud* termDroit = terme(); // lecture de l'operande droit
		term = new NoeudOperateurBinaire(operateur,term,termDroit); // const. du noeud
	}
	return term;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::terme() {
// <terme> ::= <facteur> { <opMult> facteur> }

	Noeud* fact = facteur();
	while (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		Symbole operateur = opMult();
		Noeud* factDroit = facteur();
                fact = new NoeudOperateurBinaire(operateur,fact,factDroit);
	}
        return fact;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )

	Noeud* fact=NULL;

	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>") {
		fact=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	} else if (ls.getSymCour()=="-" ||ls.getSymCour()=="non" ) {
		ls.suivant();
		// on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
		fact = new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), facteur());
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		fact=expBool();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
	return fact;
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opAdd()
// <opAdd> ::= + | -
{
    Symbole operateur;
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
        operateur=ls.getSymCour();
	ls.suivant();
        }
	else erreur("opAdd");
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opMult()
// <opAdd> ::= * | /
{       Symbole operateur;
	if (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
            operateur = ls.getSymCour();
            ls.suivant();
        }
	else
		erreur("<opMult>");
        return operateur;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBool() 
// <expBool> ::= <expBoolEt> { <opBoolOu> | <expBoolEt> }
{
    Symbole operateur;
        Noeud* operande = expBoolEt();
	while (ls.getSymCour()=="ou") {
		operateur = opBoolOu();
		Noeud* operandeDroit = expBoolEt();
                operande = new NoeudOperateurBinaire(operateur,operande,operandeDroit);
	}
        return operande;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBoolEt() 
// <expBoolEt> ::= <relation> { <opBoolEt> | <relation> }
{
    Symbole operateur;
        Noeud* operande = relation();
	while (ls.getSymCour()=="et") {
		operateur = opBoolEt();
		Noeud* operandeDroit = relation();
                operande = new NoeudOperateurBinaire(operateur,operande,operandeDroit);
                
	}
        return operande;
}    
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opBoolEt() 
// <opBool> ::= et | ou
{
    Symbole operateur;
    	if (ls.getSymCour()=="et") {
                operateur = ls.getSymCour();
                ls.suivant();
	}
                else
		erreur("<opBoolEt>");
    return operateur;
}
 ////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opBoolOu() 
// <opBoolOu> ::= ou
{
    Symbole operateur;
    	if (ls.getSymCour()=="ou") {
            operateur = ls.getSymCour();
	    ls.suivant();
        }
	else
		erreur("<opBoolOu>");
    return operateur;
}   
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::relation()
// <relation> ::= <expression> { <opRel> <expression> }
{
    Symbole operateur;
        Noeud* operande = expression();
	while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=") 
        {
		operateur = opRel();
		Noeud* operandeDroit = expression();
                operande = new NoeudOperateurBinaire(operateur,operande,operandeDroit);
	}
        return operande;
}
    
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opRel()
// <opRel> ::= == | != | < | <= | > | >=
{
    Symbole operateur;
    	if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=") {
            operateur = ls.getSymCour();
            ls.suivant();
	}
           else
		erreur("<opRel>");
    return operateur;
}
    
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opUnaire()
// <opUnaire> ::= - | non
{
    Symbole operateur;
    	if (ls.getSymCour()=="-" || ls.getSymCour()=="non") {
            operateur = ls.getSymCour();
            ls.suivant();
        }
	else
		erreur("<opUnaire>");    
    return operateur;
}
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
